//
// SrvSsiResponse.cs
//
// Copyright (c) 2007 Lukas Lipka.
//

using System;
using System.Collections.Generic;
using System.Text;

using IcqSharp;
using IcqSharp.Base;
using IcqSharp.Util;

namespace IcqSharp.Packets
{
    [SnacPacketType (0x0013, 0x0006)]
    class SrvSsiResponse : PacketHandler
    {
        private int contact_count = 0;
        private bool parsed = false;

        public SrvSsiResponse(Session session, SnacPacket packet)
            : base (session, packet)
        {
            byte version = packet.Data[0];
            ushort item_count = LittleEndianBitConverter.Big.ToUInt16 (packet.Data, 1);

            Log.Debug ("SSI version {0:X}", version);
            Log.Debug ("SSI has {0} items", item_count);

            int bytes_parsed = ParseSsiStructure (packet.Data, 3, item_count);

            // We need to check if this is not equal to
            // zero, because that means this is the last
            // packet
            uint time = LittleEndianBitConverter.Big.ToUInt32(packet.Data, bytes_parsed);

            if (time != 0)
            {
                parsed = true;
                session.ContactList.OnContactListReceived(session.ContactList, EventArgs.Empty);
            }
            
            Log.Debug ("SSI has {0} contacts", contact_count);
        }

        private int ParseSsiStructure (byte[] data, int offset, int items_count)
        {
            int current_offset = offset;

            for (int i = 0; i < items_count; i++)
            {
                current_offset += ParseSsiItem (data, current_offset);
            }

            return current_offset;
        }

        private int ParseSsiItem (byte[] data, int offset)
        {
            ushort item_name_length = LittleEndianBitConverter.Big.ToUInt16 (data, offset);
            string item_name = Encoding.UTF8.GetString (data, offset + 2, item_name_length);

            ushort group_id = LittleEndianBitConverter.Big.ToUInt16 (data, offset + 2 + item_name_length);
            ushort item_id = LittleEndianBitConverter.Big.ToUInt16 (data, offset + 4 + item_name_length);
            ushort flag = LittleEndianBitConverter.Big.ToUInt16 (data, offset + 6 + item_name_length);
            ushort data_length = LittleEndianBitConverter.Big.ToUInt16 (data, offset + 8 + item_name_length);

            if (flag == 0x00)
            {
                Contact c = new Contact (item_name);
                c.Nickname = GetNickname (data, offset + 10 + item_name_length, data_length);

                Log.Debug("Nickname: {0} ({1})", c.Nickname, c.Uin);

                Session.ContactList.Add (c);
                contact_count++;
            }

            return 10 + item_name_length + data_length;
        }

        private string GetNickname (byte[] data, int offset, int length)
        {
            TlvList tlvs = TlvList.Parse(data, offset, length);

            foreach (Tlv tlv in tlvs)
            {
                if (tlv.Type == 0x131)
                    return Encoding.UTF8.GetString (tlv.Data, 0, tlv.Length);
            }

            return null;
        }

        public override List<FlapPacket> Response (FlapPacket packet)
        {
            // This packet usually gets sent in chunks, thats why we
            // send this after the last chunk was received.
            if (!parsed)
                return null;

            List<FlapPacket> responses = new List<FlapPacket> ();

            CliSsiActivate ssi_activate = new CliSsiActivate ();
            responses.Add (ssi_activate);

            // FIXME: We should use the StatusManager to set status,
            // but currently we have no way of calling it post SsiActivate
            // because it wont take any effect earlier.            
            //CliSetStatus status = new CliSetStatus (Status.Online);
            //responses.Add (status);
            Session.StatusManager.Status = Status.Online;

            CliReady ready = new CliReady ();
            responses.Add (ready);

            // FIXME: This is incorrect here. Should be in handler for
            // CliReady response but there is none.
            Session.OnConnected (null, EventArgs.Empty);

            return responses;
        }
    }
}
